package com.purdue.edu.psychotron.server;

import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;

import com.purdue.edu.psychotron.client.service.UserService;
import com.purdue.edu.psychotron.client.entity.ChattingHistory;
import com.purdue.edu.psychotron.client.entity.ContactBook;
import com.purdue.edu.psychotron.client.entity.MessageBuffer;
import com.purdue.edu.psychotron.client.entity.User;
import com.purdue.edu.psychotron.shared.Pair;
import com.purdue.edu.psychotron.shared.Quad;
import com.purdue.edu.psychotron.shared.UUID;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

@SuppressWarnings("serial")
public class UserServiceImpl extends RemoteServiceServlet implements UserService 
{
	static
	{
		try 
		{
			ObjectifyService.register(User.class);
			ObjectifyService.register(ContactBook.class);
			ObjectifyService.register(MessageBuffer.class);
			ObjectifyService.register(ChattingHistory.class);
		} catch (Exception e) {	}
	}

	@Override
	public String register(String firstName, String lastName, String login, String password) {

		Objectify ofy = ObjectifyService.begin();
		if( ofy.query(User.class).filter("login", login).get() != null )
			return "Error: This login Already Exists, Please Choose A New One.";

		if(login.length() < 5)
			return "Error: Login Too Short.";

		if(password.length() < 6)
			return "Error: Password Too Short.";

		User user = new User.Builder(firstName, lastName, login, password).build();
		ofy.put(user);
		return "Successful!";
	}

	@Override
	public String logIn(String login, String password) {
		try {	ObjectifyService.register(User.class);	} 
		catch (Exception e) {	}


		if(login.length() < 5)
			return "Error: Invalid Login.";

		if(password.length() < 6)
			return "Error: Invalid Password.";

		Objectify ofy = ObjectifyService.begin();

		User user = ofy.query(User.class).filter("login", login).get();

		if (user == null) {
			return "Error: Incorrect Username.";
		} 
		else if(!user.getPassword().equals(password)){
			return "Error: Incorrect Password.";
		}else{
			new User.Builder(user).setStatus(User.STATUS_AVAILABLE);
			return user.getUserId();
		}
	}


	@Override
	public String logOut(String login) {
		Objectify ofy = ObjectifyService.begin();

		User user = ofy.query(User.class).filter("login", login).get();


		new User.Builder(user).setStatus(User.STATUS_UNAVAILABLE);
		return "Successful!";

	}

	@Override
	public String unsubscribe(String login) {
		Objectify ofy = ObjectifyService.begin();

		User user = ofy.query(User.class).filter("login", login).get();


		new User.Builder(user).setStatus(User.STATUS_EMBARGOED);
		new User.Builder(user).setRole(User.ROLE_INVALID);
		return "Successful!";
	}

	@Override
	public ArrayList<Pair<String,String>> getContactPairListByUerId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();
		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}
		if(contactBook.getContactList() == null)
			return null;


		ArrayList<Pair<String, String>> contactNameAndUserIdList = new ArrayList<Pair<String, String>>();
		for(String ContactId: contactBook.getContactList())
		{
			User temp = ofy.query(User.class).filter("userId", ContactId).get();
			contactNameAndUserIdList.add(new Pair<String,String>(temp.getFirstName()+" "+temp.getLastName() , ContactId));
		}

		return contactNameAndUserIdList;
	}

	@Override
	public ArrayList<Pair<String,String>> getBlockedContactPairListByUerId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();
		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getBlockedContactList() == null)
			return null;

		ArrayList<Pair<String, String>> blockedContactNameAndUserIdList = new ArrayList<Pair<String, String>>();
		for(String ContactId: contactBook.getBlockedContactList())
		{
			User temp = ofy.query(User.class).filter("userId", ContactId).get();
			blockedContactNameAndUserIdList.add(new Pair<String,String>(temp.getFirstName()+" "+temp.getLastName() , ContactId));
		}

		return blockedContactNameAndUserIdList;
	}

	@Override
	public String addNewContactByUserId(String baseUserId, String targetLogin) {
		Objectify ofy = ObjectifyService.begin();



		User targetUser = ofy.query(User.class).filter("login", targetLogin).get();
		if(targetUser==null){
			return "Invalid Target User";
		}

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", baseUserId).get();
		
		new ContactBook.Builder(contactBook).addNewContact(targetUser.getUserId()).build();
		ofy.put(contactBook);


		String baseUserFullName = getUserFullNameByUserId(baseUserId);
		String targetUserFullName = getUserFullNameByUserId(targetUser.getUserId());

		String chattingHistoryId = "";
		if(baseUserId.compareTo(targetUser.getUserId()) < 0)
			chattingHistoryId = baseUserId+targetUser.getUserId();
		else
			chattingHistoryId = targetUser.getUserId()+baseUserId;
		ChattingHistory history = ofy.query(ChattingHistory.class).filter("chattingHistoryId", chattingHistoryId).get();
		if(history == null){
			history = new ChattingHistory.Builder(baseUserId, baseUserFullName, targetUser.getUserId(), targetUserFullName).build();
			ofy.put(history);
		}
		
		inviteContactByTargetLogin(baseUserId,targetLogin);
		
		return "Successful!";
	}

	@Override
	public void sendMessageToBuffer(String senderId, String receiverId, String message) {
		String messageBufferId;
		if(senderId.compareTo(receiverId) < 0)
			messageBufferId = senderId+receiverId;
		else
			messageBufferId = receiverId+senderId;

		Objectify ofy = ObjectifyService.begin();
		MessageBuffer messageBuffer = ofy.query(MessageBuffer.class).filter("messageBufferId", messageBufferId).get();
		if(messageBuffer==null){
			messageBuffer = new MessageBuffer.Builder(senderId, receiverId).build();
		}

		new MessageBuffer.Builder(messageBuffer).addMessage(senderId, message);
		ofy.put(messageBuffer);

		String chattingHistoryId = messageBufferId;
		ChattingHistory history = ofy.query(ChattingHistory.class).filter("chattingHistoryId", chattingHistoryId).get();

		history = new ChattingHistory.Builder(history).addMessage(senderId, message).build();
		ofy.put(history);
	}

	@Override
	public String requestMessage(String requesterId, String sourceId) {
		if(requesterId== null || sourceId==null){
			return null;
		}

		String messageBufferId;
		if(requesterId.compareTo(sourceId) < 0)
			messageBufferId = requesterId+sourceId;
		else
			messageBufferId = sourceId+requesterId;
		Objectify ofy = ObjectifyService.begin();
		MessageBuffer messageBuffer = ofy.query(MessageBuffer.class).filter("messageBufferId", messageBufferId).get();
		if(messageBuffer==null){
			messageBuffer = new MessageBuffer.Builder(requesterId, sourceId).build();
		}

		String temp = messageBuffer.getContentByRequesterId(requesterId);
		messageBuffer = new MessageBuffer.Builder(messageBuffer).flushByRequesterId(requesterId).build();	
		// Attention, flush will flush the message for the requester, ie message from the source

		ofy.put(messageBuffer);
		return temp;

	}

	@Override
	public void timmer(Integer waitForNSeconds) {
		try {
			Thread.sleep(waitForNSeconds*1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	@Override
	public String getUserLoginByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();
		User user = ofy.query(User.class).filter("userId", userId).get();
		if(user==null)
			return null;
		return user.getLogin();
	}

	@Override
	public String getUserFullNameByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();
		User user = ofy.query(User.class).filter("userId", userId).get();
		if(user==null)
			return null;
		return user.getFirstName()+" "+user.getLastName();
	}

	@Override
	public void initializeCloudMessengerForUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();
		User user = ofy.query(User.class).filter("userId", userId).get();
		user = new User.Builder(user).setStatus(User.STATUS_AVAILABLE).build();
		ofy.put(user);

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();

		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

	}

	@Override
	public void disengageCloudMessengerForUserId(String userId, String targetUserId) {
		Objectify ofy = ObjectifyService.begin();
		String messageBufferId;
		if(userId.compareTo(targetUserId) < 0)
			messageBufferId = userId+targetUserId;
		else
			messageBufferId = targetUserId+userId;
		MessageBuffer messageBuffer = ofy.query(MessageBuffer.class).filter("messageBufferId", messageBufferId).get();
		ofy.delete(messageBuffer);

		User user = ofy.query(User.class).filter("userId", userId).get();
		user = new User.Builder(user).setStatus(User.STATUS_UNAVAILABLE).build();
		ofy.put(user);

	}

	@Override
	public void removeContactByUserId(String requesterId, String targetUserId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", requesterId).get();
		if(contactBook.getContactList()==null){
			new ContactBook.Builder(contactBook).initializeContactList();
			return;
		}
		new ContactBook.Builder(contactBook).removeContact(targetUserId).build();
		ofy.put(contactBook);
		return;

	}

	@Override
	public ArrayList<String> getContactListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();
		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}
		if(contactBook.getContactList() == null)
			return null;

		return contactBook.getContactList();
	}

	@Override
	public ArrayList<String> getBlockedContactListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();
		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getBlockedContactList() == null)
			return null;

		return contactBook.getBlockedContactList();
	}

	@Override
	public void blockContactForRequesterIdByTargetId(String requesterId, String targetId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", requesterId).get();
		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(requesterId).initializeContactList().build();
			ofy.put(contactBook);
		}

		new ContactBook.Builder(contactBook).blockContact(targetId);

		ofy.put(contactBook);
	}

	@Override
	public ArrayList<String> getContactNameListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();

		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getContactList() == null)
			return null;

		ArrayList<String> nameList = new ArrayList<String>();

		for(String p : contactBook.getContactList()){
			User user = ofy.query(User.class).filter("userId", p).get();
			nameList.add(user.getFirstName()+" "+user.getLastName());

		}
		return nameList;
	}

	@Override
	public ArrayList<String> getBlockedContactNameListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();

		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getBlockedContactList() == null)
			return null;	

		ArrayList<String> nameList = new ArrayList<String>();

		for(String p : contactBook.getBlockedContactList()){
			User user = ofy.query(User.class).filter("userId", p).get();
			nameList.add(user.getFirstName()+" "+user.getLastName());

		}
		return nameList;
	}


	@Override
	public String getChattingHistoryByIds(String userAId, String userBId) {
		String chattingHistoryId = "";
		if(userAId.compareTo(userBId) < 0)
			chattingHistoryId = userAId+userBId;
		else
			chattingHistoryId = userBId+userAId;
		Objectify ofy = ObjectifyService.begin();
		ChattingHistory history = ofy.query(ChattingHistory.class).filter("chattingHistoryId", chattingHistoryId).get();

		if(history == null){
			return "No History Found!";
		}
		return history.getHistoryInString()+"\r\n";
	}

	@Override
	public void clearChattingHistoryByIds(String userAId, String userBId) {
		String chattingHistoryId = "";
		if(userAId.compareTo(userBId) < 0)
			chattingHistoryId = userAId+userBId;
		else
			chattingHistoryId = userBId+userAId;
		Objectify ofy = ObjectifyService.begin();
		ChattingHistory history = ofy.query(ChattingHistory.class).filter("chattingHistoryId", chattingHistoryId).get();
		history = new ChattingHistory.Builder(history).clearHistory().build();
		ofy.put(history);
	}

	@Override
	public void inviteContactByTargetLogin(String userId, String targetLogin) {
		Objectify ofy = ObjectifyService.begin();

		User targetUser = ofy.query(User.class).filter("login", targetLogin).get();
		if(targetUser==null){
			return;
		}

		ContactBook targetContactBook = ofy.query(ContactBook.class).filter("userId", targetUser.getUserId()).get();

		new ContactBook.Builder(targetContactBook).addPendingContact(userId).build();	// Adding yourself to his pending list
		ofy.put(targetContactBook);
	}

	@Override
	public ArrayList<Quad<String, String, String, String>> getContactInfoBundleListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();

		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getContactList() == null)
			return null;	

		ArrayList<Quad<String, String, String, String>> bundleList = new ArrayList<Quad<String, String, String, String>>();
		
		Quad<String, String, String, String> temp;
		
		for(String p : contactBook.getContactList()){
			User user = ofy.query(User.class).filter("userId", p).get();
			temp = new Quad<String, String, String, String>(user.getUserId(), user.getLogin(), user.getFirstName()+" "+user.getLastName(), user.getStatus());
			bundleList.add(temp);
		}
		return bundleList;
	}
	
	@Override
	public ArrayList<Quad<String, String, String, String>> getBlockedContactInfoBundleListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();

		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getBlockedContactList() == null)
			return null;	

		ArrayList<Quad<String, String, String, String>> bundleList = new ArrayList<Quad<String, String, String, String>>();
		
		Quad<String, String, String, String> temp;
		
		for(String p : contactBook.getBlockedContactList()){
			User user = ofy.query(User.class).filter("userId", p).get();
			temp = new Quad<String, String, String, String>(user.getUserId(), user.getLogin(), user.getFirstName()+" "+user.getLastName(), user.getStatus());
			bundleList.add(temp);
		}
		return bundleList;
	}
	
	@Override
	public ArrayList<Quad<String, String, String, String>> getPendingContactInfoBundleListByUserId(String userId) {
		Objectify ofy = ObjectifyService.begin();

		ContactBook contactBook = ofy.query(ContactBook.class).filter("userId", userId).get();

		// If this user has not set up a contact list yet, we will immediately build one
		if(contactBook == null){
			contactBook = new ContactBook.Builder(userId).initializeContactList().build();
			ofy.put(contactBook);
		}

		if(contactBook.getPendingContactList() == null)
			return null;	

		ArrayList<Quad<String, String, String, String>> bundleList = new ArrayList<Quad<String, String, String, String>>();
		
		Quad<String, String, String, String> temp;
		
		for(String p : contactBook.getPendingContactList()){
			User user = ofy.query(User.class).filter("userId", p).get();
			temp = new Quad<String, String, String, String>(user.getUserId(), user.getLogin(), user.getFirstName()+" "+user.getLastName(), user.getStatus());
			bundleList.add(temp);
		}
		return bundleList;
	}

	@Override
	public void acceptContactByTargetLogin(String userId, String targetId) {
		Objectify ofy = ObjectifyService.begin();

		User targetUser = ofy.query(User.class).filter("userId", targetId).get();
		if(targetUser==null){
			return;
		}

		ContactBook myContactBook = ofy.query(ContactBook.class).filter("userId", userId).get();
		new ContactBook.Builder(myContactBook).acceptContact(targetId).build();	// Adding him to your contact list
		ofy.put(myContactBook);
		
		ContactBook targetContactBook = ofy.query(ContactBook.class).filter("userId", targetId).get();
		new ContactBook.Builder(targetContactBook).onContactAcception(targetId).build();	// Add yourself to his contact list also
		ofy.put(targetContactBook);
	}

	@Override
	public void rejectContactByTargetLogin(String userId, String targetId) {
		Objectify ofy = ObjectifyService.begin();

		User targetUser = ofy.query(User.class).filter("userId", targetId).get();
		if(targetUser==null){
			return;
		}

		ContactBook myContactBook = ofy.query(ContactBook.class).filter("userId", userId).get();
		new ContactBook.Builder(myContactBook).rejectContact(targetId).build();	// remove him from your contact list
		ofy.put(myContactBook);
		
		ContactBook targetContactBook = ofy.query(ContactBook.class).filter("userId", targetId).get();
		new ContactBook.Builder(targetContactBook).onContactAcception(targetId).build();	// remove yourself from his contact list also
		ofy.put(targetContactBook);
		
	}


}
